package com.Akronmcp.hta.obj;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.annotation.Nullable;

import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BookMeta;
import org.bukkit.inventory.meta.ItemMeta;

import com.google.gson.JsonArray;

import io.netty.buffer.Unpooled;
import me.clip.placeholderapi.PlaceholderAPI;


//import net.minecraft.server.v1_12_R1.*;
//跃动书本
public class HopBook extends HPar
{
	
	static String mversion = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
	//mc版本
	
    static String objpre = "org.bukkit.craftbukkit." + mversion + ".";
    //org类前缀
    
    static String nmspre = "net.minecraft.server." + mversion + ".";
    //nms类前缀
    
	static Constructor<?> packetDataSerializer;
    static Constructor<?> packetPlayOutCustomPayload;
    static Method a;
    static Method getHandle;
    static Class<?> enumHandClanm;
    static Class<?> craftPlayer;
    static Enum<?> MAIN_HAND;
    static Field playerConnection;
    static Method sendPacket;
    static Class<?> ItemStackClanm;
    static Class<?> ItemStackClaob;
    static Class<?> NBTBase;
    static Class<?> NBTTagCompoundClanm;
    static Class<?> NBTTagList;
    static Class<?> NBTTagString;
    static Class<?> packetDSClanm;
    static Class<?> playerConnectionClanm;
    static Class<?> packetPlayOutCustomPayloadClanm;
    
    static Method ItemStackClanm_setTag;
    static Method asNMSCopy;
    static Method asBukkitCopy;
    static Method NBTTagCompoundClanm_set;
    static Method NBTTagList_add;
    static Method getTag;
    
    static Object packetDSer;
    
	Map<String,HopChat> htxm = new LinkedHashMap<String,HopChat>();
	
	private HopChat prehtx;
	private HopChat sufhtx;
	
	String title = "deepdarkfantasy";
	String author = "van";
	
	String tid;
	//lore内的id,用于识别
	
	String extra;
	//额外内容,用于处理批量文字

    boolean isc = false;
	//是否已经创建书本
    
	boolean isSep = false;
	//是否为分页模式
		
	
	ItemStack it = new ItemStack(Material.WRITTEN_BOOK,1);
	//书本(hopbook)实例物品
	
	static
	{
		try
		{
		    ItemStackClanm = Class.forName(nmspre+"ItemStack");
		    ItemStackClaob = Class.forName(objpre+"inventory.CraftItemStack");
		    NBTBase =  Class.forName(nmspre+"NBTBase");
		    NBTTagCompoundClanm =  Class.forName(nmspre+"NBTTagCompound");
		    NBTTagList =  Class.forName(nmspre+"NBTTagList");
		    NBTTagString =  Class.forName(nmspre+"NBTTagString");

			packetDSClanm = Class.forName(nmspre+"PacketDataSerializer");
            playerConnectionClanm = Class.forName(nmspre+"PlayerConnection");
            packetPlayOutCustomPayloadClanm = Class.forName(nmspre+"PacketPlayOutCustomPayload");
			
            
			craftPlayer = Class.forName(objpre+"entity.CraftPlayer");
			getHandle = craftPlayer.getDeclaredMethod("getHandle");
			getHandle.setAccessible(true);
			
            playerConnection = Class.forName(nmspre+"EntityPlayer").getDeclaredField("playerConnection");
            playerConnection.setAccessible(true);
            
            sendPacket = playerConnectionClanm.getDeclaredMethod("sendPacket", Class.forName(nmspre+"Packet"));
            sendPacket.setAccessible(true);
            
            packetDataSerializer = packetDSClanm.getConstructor(Class.forName("io.netty.buffer.ByteBuf"));
            packetDataSerializer.setAccessible(true);
            
            packetPlayOutCustomPayload = packetPlayOutCustomPayloadClanm.getConstructor(String.class, packetDSClanm);
            
			
            a = packetDSClanm.getMethod("a", Enum.class);
            enumHandClanm = Class.forName(nmspre+"EnumHand");
            
            packetDSer = packetDataSerializer.newInstance(Unpooled.buffer());
            
            if (enumHandClanm.isEnum())
            {
            	MAIN_HAND =
            	(Enum<?>) enumHandClanm.getDeclaredMethod
            	("valueOf",String.class).invoke(null,"MAIN_HAND");
            	
            	/*
                Object[] enumConstants;
                for (int length = (enumConstants = enumHandClanm.getEnumConstants()).length, i = 0; i < length; i++) 
                {//提取枚举
                    final Object o = enumConstants[i];
                    if (o.toString().equals()) {
                        MAIN_HAND = (Enum<?>)o;
                    }
                }
                */
            	a.invoke(packetDSer, MAIN_HAND);
            }
            
             ItemStackClanm_setTag
            = ItemStackClanm.getDeclaredMethod("setTag",NBTTagCompoundClanm);
            ItemStackClanm_setTag.setAccessible(true);
            
            asNMSCopy
            = ItemStackClaob.getDeclaredMethod("asNMSCopy",ItemStack.class);
            asNMSCopy.setAccessible(true);
                        
            asBukkitCopy
            = ItemStackClaob.getDeclaredMethod("asBukkitCopy",ItemStackClanm);
             asBukkitCopy.setAccessible(true);
             
             getTag
             = ItemStackClanm.getDeclaredMethod("getTag");
              getTag.setAccessible(true);
            
            NBTTagCompoundClanm_set
            = NBTTagCompoundClanm.getDeclaredMethod("set",String.class,NBTBase);
            NBTTagCompoundClanm_set.setAccessible(true);
            
            NBTTagList_add
            = NBTTagList.getDeclaredMethod("add",NBTBase);
            NBTTagList_add.setAccessible(true);
            
           //反射部分,用于预备处理书本tag
		}catch(Exception e)
		{
			e.printStackTrace();
			System.out.print("nms语句错误,当前版本不支持hopbook部分功能");
		}
	}
	
	
	
	public HopBook(HManager hta) 
	{
		this.hta = hta;
	}
	
	public HopBook() {}
	
	
	/**
	 * 生成书籍对象,参数为:htx集合,要赋予的书籍对象,papi对应玩家
	 * **/
	@Nullable
	public ItemStack createBy(Collection<HopChat> htxl2,ItemStack item,Player p)
	{//生成书籍对象,通过htx集合,要赋予的书籍对象,papi对应玩家
		try
		{
		 Constructor<?> cons1 = NBTTagString .getConstructor(String.class);
         
		 Object nmsbook = asNMSCopy.invoke(null,item);
         Object tag = getTag.invoke(nmsbook);//NBTTagCompoundClanm.newInstance();
         Object taglist = NBTTagList.newInstance();
         //预定义nms物品及其taglist
         
         
         for(HopChat htx:htxl2)
         {//遍历htx
        	 if(htx==null)continue;
        	 
        	 String json = "[";
        	 
        	 if(getPrehtx()!=null)
	         {
	        	 json+=prehtx.toJsonString();
	        	 json+=",";
	         }
        	 //加入htx的前缀json
        	 
        	 json+=htx.toJsonString();
        	 //加入htx的json
        	 
        	 if(getSufhtx()!=null)
        	 {
        		 json+=",";
        		 json+=sufhtx.toJsonString();
        	 }
        	 //加入htx的后缀json
        	 
        	 json+="]";
        	 
        	 String htxstr = json;
        	 
        	if(p!=null&&papi)
        	{//解析papi
        		htxstr = PlaceholderAPI.setPlaceholders(p,htxstr);
        	}
        	  Object tagstring = cons1.newInstance(htxstr);
        	  //根据字符串生成tag
        	  
        	  NBTTagList_add.invoke(taglist, tagstring);
        	  //加入tag到tag集合
        	  
         }
         
         NBTTagCompoundClanm_set.invoke(tag,"pages",taglist);
         ItemStackClanm_setTag.invoke(nmsbook, tag);
         //设置(覆盖)nms物品的pages部分的tag
         
         return (ItemStack) asBukkitCopy.invoke(null,nmsbook);
          //生成nms物品,返回
         
		}catch(Exception e)
		{
			e.printStackTrace();
		}
		
		return null;
         
         
	}

	/**
	 * 根据设置创建书本
	 *  参数为:papi解析玩家
	 * **/
    @Nullable
	public void createBook(Player p)
	{//创建书本
			
		if(isSep)
		{//如果为分页模式
			if(id==null)
			{
				return;
			}
				
			for(HopChat v:htxm.values())
			{
				it = createBy(Arrays.asList(v),it,p);
				break;
			}
			
			ItemMeta im = it.getItemMeta();
			
			List<String> tl = im.getLore();
			
			int ti = 0;
			if(tl==null)
			tl = new ArrayList<String>();	
				
			for(int i=0;i<tl.size();i++)
			{
			   if(tl.get(i).contains("§一"))
			   {
				   tl.remove(i);
				   ti = i;
				   break;
			   }
			}
			
			tl.add(ti,
			("§一§6[§9'"+1+"§页§b/§9'"+htxm.size()+"§总§6] "
					+"§6(§b'"+1+"§签§6)"+"§I"+tid+"§D"));
			im.setLore(tl);
			it.setItemMeta(im);
			//生成lore,储存书本书签页面等信息,使用['内容§单个中文]来识别内容
			
		}else
		{//普通模式
			it = createBy(htxm.values(),it,p);
		}
		isc = true;
	}
	
    /**
        * 添加页面
        * 参数为htx对象
     * **/
	public void addHPage(HopChat htx)
	{
		htxm.put(htx.getId(),htx);
	}
	
	
	/**让玩家打开手上书本**/
	public static void letOpen(Player p)
	{
		try
		{
		 final Object entityPlayer = getHandle.invoke(p);
		 final Object pc = playerConnection.get(entityPlayer);
         sendPacket.invoke(pc,packetPlayOutCustomPayload.newInstance("MC|BOpen", packetDSer));
		
		}catch(Exception e)
		{
		  e.printStackTrace();
		}
		 
	}
	
	/**
	 * 让玩家直接打开一个由输入htx生成的书本页面
	 * 参数为:玩家,htx,是否解析papi
	 * **/
	public static void openToPage(Player p,HopChat htx,boolean ispapi)
	{
		if(!p.isOnline())
		return;
			
		int slot = p.getInventory().getHeldItemSlot();
		ItemStack bo = p.getInventory().getItem(slot);
		
		ItemStack sbo = bo;//储存
		
		ItemStack tbo = new ItemStack(Material.WRITTEN_BOOK,1);
		BookMeta im2 = (BookMeta) tbo.getItemMeta();
		im2.addPage("233");
		tbo.setItemMeta(im2);
		
		try
		{
		 Constructor<?> cons1 = NBTTagString .getConstructor(String.class);
         
		 Object nmsbook = asNMSCopy.invoke(null,tbo);
         Object tag = getTag.invoke(nmsbook);//NBTTagCompoundClanm.newInstance();
         Object taglist = NBTTagList.newInstance();
         
         String htxstr = htx.toJsonString();
        	         	 
         if(ispapi)
         htxstr = PlaceholderAPI.setPlaceholders(p,htxstr);
        	
         Object tagstring = cons1.newInstance(htxstr);
         NBTTagList_add.invoke(taglist, tagstring);
         
         
        
         NBTTagCompoundClanm_set.invoke(tag,"pages",taglist);
         ItemStackClanm_setTag.invoke(nmsbook, tag);
         
         tbo = (ItemStack) asBukkitCopy.invoke(null,nmsbook);
          
         
		}catch(Exception e)
		{
			e.printStackTrace();
		}
		
		p.getInventory().setItem(slot, tbo);
		letOpen(p);
		
		p.getInventory().setItem(slot, sbo);//还原
	}

	/**
	 * 跳转到书签
	 * */
	public void toMarkPage(Player p)
	{
		openPage(p,getMarkPage(p)); 
	}
	
	
	public void openPage(Player p,String page)
	{
		int size = htxm.size();
		
		HopChat htx = htxm.get(page);
		if(htx==null)
		{
			p.sendMessage("莫得此页:"+page);
			return;
		}
		
		int pagen=1;
		for(String k:htxm.keySet())
		{
			if(page.equals(k))
				break;
			pagen++;
		}
		
		int slot = p.getInventory().getHeldItemSlot();
		ItemStack bo = p.getInventory().getItem(slot);
		
		BookMeta im = (BookMeta) bo.getItemMeta();
		
		if(checkEqual(bo))
		{
			List<String> il = im.getLore();
			String ol = il.get(0);
			il.remove(0);
			ol = ol.replaceAll("'\\d*§页","'"+pagen+"§页");
			ol = ol.replaceAll("'\\d*§总","'"+size+"§总");
			il.add(0,ol);

			im.setLore(il);
			bo.setItemMeta(im);
			
			bo = createBy(Arrays.asList(htx), bo,p);
			
			p.getInventory().setItem(slot, bo);
			
			letOpen(p);
		}
	}
	
	/**
	 * 跳转到页面
	 * */
	public void openPage(Player p,int page)
	{
		int size = htxm.size();
		
		if(size==0)
		{
			p.sendMessage("该书无页..");
			return;
		}
		
		if(page<1)
		{
			page = size;
		}
		if(page>size)
		{
			page = 1;
		}
			
		int slot = p.getInventory().getHeldItemSlot();
		ItemStack bo = p.getInventory().getItem(slot);
		
		HopChat htx = null;
		int i=0;
		for(String k:htxm.keySet())
		{
			if(page-1==i)
			{
				htx=htxm.get(k);
				break;
			}
			i++;
		}
		
		BookMeta im = (BookMeta) bo.getItemMeta();
		
		if(checkEqual(bo))
		{
			List<String> il = im.getLore();
			String ol = il.get(0);
			il.remove(0);
			ol = ol.replaceAll("'\\d*§页","'"+page+"§页");
			ol = ol.replaceAll("'\\d*§总","'"+size+"§总");
			il.add(0,ol);

			im.setLore(il);
			bo.setItemMeta(im);
			
			bo = createBy(Arrays.asList(htx), bo,p);
			
			p.getInventory().setItem(slot, bo);
			
			letOpen(p);
		}
		
	}
	
	/**下一页*/
	public void nextPage(Player p)
	{
		openPage(p,getCurPage(p)+1);
	}
	
	/**上一页*/
	public void lastPage(Player p)
	{
		openPage(p,getCurPage(p)-1);
	}
	
	public Map<String, HopChat> getPages()
	{
		return htxm;
	}
	
	/**根据lore获取当前页面*/
	public int getCurPage(Player p)
	{
		int slot = p.getInventory().getHeldItemSlot();
		ItemStack bo = p.getInventory().getItem(slot);
		int pa = 1;
		
		List<String> tl1 = bo.getItemMeta().getLore();
		String lo = null;
		
		if(tl1!=null)
		if(tl1.size()>0)
		{
			lo = tl1.get(0);
			Pattern r = Pattern.compile("'\\d*§页");
			Matcher m = r.matcher(lo);
			
			if(m.find())
			{
			   String ts0 = m.group(0);
			   int b = ts0.indexOf("'");
			   int e = ts0.indexOf("§");
			   String ts = ts0.substring(b+1,e);
			   pa = Integer.valueOf(ts);
			}
			
		}
		return pa;
		
	}

	/**获取书签页面*/
	public int getMarkPage(Player p)
	{
		int slot = p.getInventory().getHeldItemSlot();
		ItemStack bo = p.getInventory().getItem(slot);
		int pa = 1;
		
		List<String> tl1 = bo.getItemMeta().getLore();
		String lo = null;
		
		if(tl1!=null)
		if(tl1.size()>0)
		{
			lo = tl1.get(0);
			Pattern r = Pattern.compile("'\\d*§签");
			Matcher m = r.matcher(lo);
			
			if(m.find())
			{
			   String ts0 = m.group(0);
			   int b = ts0.indexOf("'");
			   int e = ts0.indexOf("§");
			   String ts = ts0.substring(b+1,e);
			   pa = Integer.valueOf(ts);
			}
			
		}
		return pa;
		
	}
	
	/**给予玩家*/
  	public void give(List<Player> pl)
	{
		try 
		{
			for(Player p:pl)
			{
				if(htxm.size()==0)
				{
					p.getInventory().addItem(it);
					continue;
				}
				
				if(isSep||papi||!isc)
				 createBook(p);
				
			     p.getInventory().addItem(it);
			}
				
		}catch(Exception e)
		{
			e.printStackTrace();
		}
	}

  	/**给予一个玩家*/
	public void give(Player p)
	{
		give(Arrays.asList(p));
	}
	
	/**给予全部*/
	public void giveToAll()
	{
		give(new ArrayList<Player>(Bukkit.getOnlinePlayers()));
	}

	
	public void setMark(Player p,int page)
	{	
		int slot = p.getInventory().getHeldItemSlot();
		ItemStack bo = p.getInventory().getItem(slot);
		BookMeta im = (BookMeta) bo.getItemMeta();
		
		if(checkEqual(bo))
		{
			List<String> il = im.getLore();
			String ol = il.get(0);
			il.remove(0);
			il.add(0,ol.replaceAll("'\\d*§签","'"+page+"§签"));
			
			im.setLore(il);
			bo.setItemMeta(im);
			p.getInventory().setItem(slot, bo);
			
			openPage(p, page);
		}
	}

	/**设置书签为当前玩家页面*/
	public void setMark(Player p)
	{
		setMark(p,getCurPage(p));
	}
	
	public static String getID(ItemStack bo)
	{
		List<String> tlore = bo.getItemMeta().getLore();
		
		String id = null;
		String lo = null;
		
		if(tlore!=null&&!tlore.isEmpty())
		{
			lo = tlore.get(0);
		}else
		{
			return null;
		}
		
		int b = lo.indexOf("§I");
		int e = lo.indexOf("§D");
		
		if(b!=-1&&e!=-1)
		{//读取id
			String str1 = lo.substring(b+2, e);
			id = str1.replace("§", "");
		}else
		{
		   return null;
		}
		
		return id;
	}
	
	/**检查物品是否为该hopbook实例物品*/
	public boolean checkEqual(ItemStack bo)
	{
		
		if(bo!=null
		&&!bo.getItemMeta().getLore().isEmpty())
		{
		 List<String> tl = bo.getItemMeta().getLore();
		 for(int i=0;i<tl.size();i++)
		 {
			 if(tl.get(i).contains("§一"));
			 if(tl.get(i).contains(tid))
			 {
				return true;
			 }
			 
		 }
			
		}
		
		return false;
		
	}
	
	/**获取实例物品*/
	public ItemStack getItemBook()
	{
		return it;
	}
	
	
	public String getId() {
		return id;
	}

	public void setId(String id)
	{
		this.id = id;
		
		StringBuffer ttid = new StringBuffer(id);
		for(int i=1;i<=id.length();i++)
		{
			ttid.insert(id.length()-i, "§");
		}
		tid = ttid.toString();
		
	}
	
	public void addToList()
	{
		hta.addBook(this);
	}
	
	public void addToList(String id)
	{
		setId(id);
		hta.addBook(this);
	}

	
	public void setPapi(boolean ispapi)
	{
		papi = ispapi;
	}

	/**判断是否为分页模式*/
	public void setSep(boolean isSep)
	{
		this.isSep = isSep;
	}
	
	/**设置书本额外内容,用于处理批量文字*/
	public void setExtra(String ex)
	{
		extra = ex;
		
		ex = ex.replace("\\n", " ");
		int le = ex.length();
		
		int a = 0;
		int b = 0;
		
		if(prehtx!=null)
		a=12;
		
		if(sufhtx!=null)
		b=12;
		
		int pmax = 160 - a - b;
		//缩短单页文本最大长度
		//防止溢出,仅限前后缀各仅限一行
		
		for(int i=0;i<le;i=i+pmax)
		{//分割文本,生成页面加入尾部
			int e = i+pmax;
			if(e>le)
			e=le;
			
			String str = ex.substring(i,e);
						
			HopChat ht = new HopChat(hta);
			ht.setText(str);
			ht.create();
			htxm.put(i+"ex",ht);
		}
	}

	/**获取额外内容*/
	public String getExtra()
	{
		return extra;
	}
	
	public boolean isSep()
	{
		return isSep;
	}
	
	public boolean isPapi() 
	{
		return papi;
	}

	public HopChat getPrehtx() {
		return prehtx;
	}
	
	/**设置前缀页面*/
	public void setPrehtx(HopChat prehtx) {
		this.prehtx = prehtx;
	}

	public HopChat getSufhtx() {
		return sufhtx;
	}
	
	/**设置后缀页面*/
	public void setSufhtx(HopChat sufhtx) {
		this.sufhtx = sufhtx;
	}
	
	/**直接为玩家显示此hopbook的页面,但不给予hopbook物品,仅限普通模式*/
	public void send(List<Player> pl)
	{
		if(papi)
		{
			for(Player p:pl)
			{
				sendBy(p,PlaceholderAPI.setPlaceholders(p, text),false);
			}
		}else
		{
			sendBy(pl,text,false);
		}
			
	}
	
	/**直接为玩家显示此hopbook的页面,但不给予hopbook物品,仅限普通模式*/
	public void sendToAll()
	{	
		sendtoallBy(text,papi);
	}
	
	
	/**直接把文本转为在书的页面显示给玩家*/
	public static void sendBy(Player p,String text,boolean ispapi)
	{
		sendBy(Arrays.asList(p),text,ispapi);
	}

	/**直接把文本转为在书的页面显示给玩家,主程序*/
	public static void sendBy(List<Player> pl,String text,boolean ispapi)
	{
		HopChat htx = new HopChat(new HManager());
	       htx.setText(text);
	       htx.create();
	    
	    for(Player p:pl)
	    openToPage(p, htx,ispapi);
	      
	}
	
	/**直接把文本转为在书的页面显示给全部在线玩家*/
	public static void sendtoallBy(String text,boolean ispapi)
	{
		sendBy(new ArrayList<Player>(Bukkit.getOnlinePlayers()),text,ispapi);
	}
}
